﻿using Aliyun.OSS;
using Aliyun.OSS.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
namespace Ct_Aliyun
{
    public class Aliyun_SDK
    {


        private string AccessKeyId = "LTAI5t87LnK6rSfhxbePUzTW";

        private string AccessKeySecret = "3gMXCjnDmGQvuDtBUyIQYS6eWgNJ3m";

        private string Endpoint = "oss-cn-beijing.aliyuncs.com";

        private float progress = 0;


        private OssTaskRequest ossTaskBackInfo;
        public float GetProgress()
        {
            return progress;
        }

        /// <summary>
        /// 创建SDK实例
        /// </summary>
        /// <param name="AccessKeyId"></param>
        /// <param name="AccessKeySecret"></param>
        /// <param name="Endpoint"></param>
        /// <returns></returns>
        public Aliyun_SDK(string AccessKeyId, string AccessKeySecret, string Endpoint, OssTaskRequest ossTaskBackInfo)
        {

            this.AccessKeyId = AccessKeyId;
            this.AccessKeySecret = AccessKeySecret;
            this.Endpoint = Endpoint;
            this.ossTaskBackInfo = ossTaskBackInfo;
        }
        public Aliyun_SDK(string AccessKeyId, string AccessKeySecret, string Endpoint)
        {

            this.AccessKeyId = AccessKeyId;
            this.AccessKeySecret = AccessKeySecret;
            this.Endpoint = Endpoint;

        }



        #region 上传


        public bool UploadObject(string BucketName, string LocalFilePath, string OssFileDir, int Timeout, string OssFileName = "")
        {

            OssClient ossClient;
 

            try
            {
                if (Timeout != -1)
                {
                    var _configuration = new ClientConfiguration();
                    _configuration.ConnectionTimeout = Timeout;
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret, _configuration);
                }
                else
                {
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret);

                }
                if (OssFileName == "")
                {
                    OssFileName = System.DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss");
                }
                ossClient.PutObject(BucketName, Path.Combine(OssFileDir, OssFileName), LocalFilePath);
                   Console.WriteLine("Put object:{0} succeeded", OssFileDir);

                return true;
            }
            catch (OssException ex)
            {
                   Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);

                return false;
            }
            catch (Exception ex)
            {
                   Console.WriteLine("Failed with error info: {0}", ex.Message);

                return false;
            }
        }


        public bool UploadObjectRawData(string BucketName, byte[] Data, string OssFileDir, int Timeout, string OssFileName = "")
        {

            OssClient ossClient;


            try
            {
                if (Timeout != -1)
                {
                    var _configuration = new ClientConfiguration();
                    _configuration.ConnectionTimeout = Timeout;
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret, _configuration);
                }
                else
                {
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret);
                }
                if (OssFileName == "")
                {

                    OssFileName = System.DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss");
                }


                using (MemoryStream memoryStream = new MemoryStream(Data))
                {
                    ossClient.PutObject(BucketName, Path.Combine(OssFileDir, OssFileName), memoryStream);
                    Console.WriteLine("Put object:{0} succeeded", OssFileDir);

                }

                return true;
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                 ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);

                return false;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);

                return false;
            }
        }






        public async Task<bool> UploadObjectWithProgress(string BucketName, string LocalFilePath, string OssFileDir, int Timeout, string OssFileName = "")
        {


            Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
            string key = "";
            OssClient ossClient;
            try
            {
                if (Timeout != -1)
                {
                    var _configuration = new ClientConfiguration();
                    _configuration.ConnectionTimeout = Timeout;
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret, _configuration);
                }
                else
                {
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret);

                }

                if (OssFileName == "")
                {
                    FileInfo fileInfo = new FileInfo(LocalFilePath);
                    OssFileName = fileInfo.Name;
                }
                key = Path.Combine(OssFileDir, OssFileName);




                using (var fs = File.Open(LocalFilePath, FileMode.Open))
                {
                    var putObjectRequest = new PutObjectRequest(BucketName, key, fs);
                    putObjectRequest.StreamTransferProgress += streamProgressCallback;
                    ossClient.PutObject(putObjectRequest);
                }
                Console.WriteLine("Put object:{0} succeeded", key);
                ossTaskBackInfo.completed = true;
                return true;
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                 ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
                ossTaskBackInfo.completed = true;
                return false;
            }
            catch (Exception ex)
            {
                ossTaskBackInfo.completed = true;
                Console.WriteLine("Failed with error info: {0}", ex.Message);
                return false;
            }



        }



        public async Task<bool> UploadObjectRawDateaWithProgress(string BucketName, byte[] Data, string OssFileDir, int Timeout, string OssFileName = "")
        {




            OssClient ossClient;
            try
            {
                if (Timeout != -1)
                {
                    var _configuration = new ClientConfiguration();
                    _configuration.ConnectionTimeout = Timeout;
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret, _configuration);
                }
                else
                {
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret);

                }

                if (OssFileName == "")
                {

                    OssFileName = System.DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss");
                }



                using (MemoryStream memoryStream = new MemoryStream(Data))
                {

                    var putObjectRequest = new PutObjectRequest(BucketName, Path.Combine(OssFileDir, OssFileName), memoryStream);
                    putObjectRequest.StreamTransferProgress += streamProgressCallback;
                    ossClient.PutObject(putObjectRequest);
               

                }

                Console.WriteLine("Put object:{0} succeeded", OssFileDir);
                ossTaskBackInfo.completed = true;
                return true;
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                 ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
                ossTaskBackInfo.completed = true;
                return false;
            }
            catch (Exception ex)
            {
                ossTaskBackInfo.completed = true;
                Console.WriteLine("Failed with error info: {0}", ex.Message);
                return false;
            }



        }


        /// <summary>
        /// 切片上传本地大文件
        /// </summary>
        /// <param name="BucketName"></param>
        /// <param name="LocalFilePath"></param>
        /// <param name="OssFileDir"></param>
        /// <param name="Timeout"></param>
        /// <param name="OssFileName"></param>
        /// <returns></returns>
        public async Task<bool> UploadMultipartWithProgress(string BucketName, string LocalFilePath, string OssFileDir, int Timeout, string OssFileName = "")
        {
               Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());

            string key = "";
            OssClient ossClient;
            try
            {
                if (Timeout != -1)
                {
                    var _configuration = new ClientConfiguration();
                    _configuration.ConnectionTimeout = Timeout;
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret, _configuration);
                }
                else
                {
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret);

                }

                if (OssFileName == "")
                {
                    FileInfo fileInfo = new FileInfo(LocalFilePath);
                    OssFileName = fileInfo.Name;
                }
                key = Path.Combine(OssFileDir, OssFileName);

                // 初始化分片上传任务
                var initRequest = new InitiateMultipartUploadRequest(BucketName, key);
                var initResult = ossClient.InitiateMultipartUpload(initRequest);

                // 设置每块为 1M
                const int partSize = 1024 * 1024 * 1;
                var partFile = new FileInfo(LocalFilePath);
                // 计算分块数目
                var partCount = CalculatePartCount(partFile.Length, partSize);

                // 新建一个List保存每个分块上传后的ETag和PartNumber
                var partETags = new List<PartETag>();
                //upload the file
                using (var fs = new FileStream(partFile.FullName, FileMode.Open))
                {
                    for (var i = 0; i < partCount; i++)
                    {
                        // 跳到每个分块的开头
                        long skipBytes = partSize * i;
                        fs.Position = skipBytes;

                        // 计算每个分块的大小
                        var size = partSize < partFile.Length - skipBytes ? partSize : partFile.Length - skipBytes;

                        // 创建UploadPartRequest，上传分块
                        var uploadPartRequest = new UploadPartRequest(BucketName, key, initResult.UploadId)
                        {
                            InputStream = fs,
                            PartSize = size,
                            PartNumber = (i + 1)
                        };
                        uploadPartRequest.StreamTransferProgress += streamProgressCallback;
                        var uploadPartResult = ossClient.UploadPart(uploadPartRequest);

                        // 将返回的PartETag保存到List中。
                        partETags.Add(uploadPartResult.PartETag);
                    }
                }

                // 提交上传任务
                var completeRequest = new CompleteMultipartUploadRequest(BucketName, key, initResult.UploadId);
                foreach (var partETag in partETags)
                {
                    completeRequest.PartETags.Add(partETag);
                }
                ossClient.CompleteMultipartUpload(completeRequest);

                   Console.WriteLine("Multipart upload object:{0} succeeded", key);
                ossTaskBackInfo.completed = true;
                return true;
            }
            catch (OssException ex)
            {
                   Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
                ossTaskBackInfo.completed = true;
                return false;
            }
            catch (Exception ex)
            {
                   Console.WriteLine("Failed with error info: {0}", ex.Message);
                ossTaskBackInfo.completed = true;
                return false;
            }







        }


       






        #endregion

        #region 下载


        public bool DownloadObject(string bucketName, string OssFilePath, string DownloadLocalDir, int Timeout = -1, string SaveFileName = "")
        {


            string OssFileName = "";
            string SavePath = "";
            OssClient ossClient;
            try
            {
                OssFilePath.Replace("\\", "/");
                if (Timeout != -1)
                {
                    var _configuration = new ClientConfiguration();
                    _configuration.ConnectionTimeout = Timeout;
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret, _configuration);
                }
                else
                {
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret);

                }



                var result = ossClient.GetObject(bucketName, OssFilePath);

                using (var requestStream = result.Content)
                {

                    int index = OssFilePath.LastIndexOf('/');

                    if (index != -1)
                    {
                        OssFileName = OssFilePath.Substring(index + 1, OssFilePath.Length - index - 1);
                    }
                    else
                        OssFileName = OssFilePath;



                    if (SaveFileName != "")
                        SavePath = Path.Combine(DownloadLocalDir, SaveFileName);
                    else
                        SavePath = Path.Combine(DownloadLocalDir, OssFileName);


                    using (var fs = File.Open(SavePath, FileMode.Create))
                    {
                        int length = 4 * 1024;
                        var buf = new byte[length];
                        do
                        {
                            length = requestStream.Read(buf, 0, length);
                            fs.Write(buf, 0, length);
                        } while (length != 0);

                        Console.WriteLine(length);

         
                    }
                }

                   Console.WriteLine("Get object succeeded");
                return true;
            }
            catch (OssException ex)
            {
                   Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
                return false;
            }
            catch (Exception ex)
            {
                   Console.WriteLine("Failed with error info: {0}", ex.Message);
                   Console.WriteLine("Failed with error path info: {0}", SavePath);
                return false;
            }
        }

        public byte[] DownLaodObjectRawData(string bucketName, string OssFilePath, int Timeout = -1)
        {
            byte[] res;
            string OssFileName = "";
            OssClient ossClient;
            try
            {
                OssFilePath.Replace("\\", "/");
                if (Timeout != -1)
                {
                    var _configuration = new ClientConfiguration();
                    _configuration.ConnectionTimeout = Timeout;
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret, _configuration);
                }
                else
                {
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret);

                }



                var result = ossClient.GetObject(bucketName, OssFilePath);

                using (var requestStream = result.Content)
                {



                    using (MemoryStream ms = new MemoryStream())

                    {
                        const int bufferLength = 1024*4;
                        int actual;
                        byte[] buffer = new byte[bufferLength];
                        while ((actual = requestStream.Read(buffer, 0, bufferLength)) > 0)
                        {
                            ms.Write(buffer, 0, actual);
                        }
                            ms.Position = 0;

                        BinaryReader binaryReader = new BinaryReader(ms);
                        res= binaryReader.ReadBytes((int)ms.Length);

                    }
                    



                }

                Console.WriteLine("Get object succeeded");
                return res;
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                 ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
                return null;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);

                return null;
            }

        }

        public async Task<byte[]> DownLaodObjectRawDatatWithProgress(string bucketName, string OssFilePath, int Timeout = -1)
        {


            progress = 0;
            byte[] res;
            string OssFileName = "";
            OssClient ossClient;
            try
            {
                OssFilePath.Replace("\\", "/");
                if (Timeout != -1)
                {
                    var _configuration = new ClientConfiguration();
                    _configuration.ConnectionTimeout = Timeout;
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret, _configuration);
                }
                else
                {
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret);

                }


                var getObjectRequest = new GetObjectRequest(bucketName, OssFilePath);
                getObjectRequest.StreamTransferProgress += streamProgressCallback;
                var ossObject = ossClient.GetObject(getObjectRequest);
                using (var requestStream = ossObject.Content)
                {

                    using (MemoryStream ms = new MemoryStream())

                    {
                        const int bufferLength = 1024 * 4;
                        int actual;
                        byte[] buffer = new byte[bufferLength];
                        while ((actual = requestStream.Read(buffer, 0, bufferLength)) > 0)
                        {
                            ms.Write(buffer, 0, actual);
                        }
                        ms.Position = 0;

                        BinaryReader binaryReader = new BinaryReader(ms);
                        res = binaryReader.ReadBytes((int)ms.Length);

                    }

                }


                Console.WriteLine("Get object:{0} succeeded", OssFilePath);
                ossTaskBackInfo.completed = true;
                return res;
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                 ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
                ossTaskBackInfo.completed = true;
                return null;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
                ossTaskBackInfo.completed = true;
                return null;

            }








        }





        public async Task<bool> DownloadObjectWithProgress(string bucketName, string OssFilePath, string DownloadLocalDir, int Timeout = -1, string SaveFileName = "")
        {

               Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
            progress = 0;
            string OssFileName = "";
            string SavePath = "";
            OssClient ossClient;
            try
            {
                OssFilePath.Replace("\\", "/");
                if (Timeout != -1)
                {
                    var _configuration = new ClientConfiguration();
                    _configuration.ConnectionTimeout = Timeout;
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret, _configuration);
                }
                else
                {
                    ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret);

                }


                var getObjectRequest = new GetObjectRequest(bucketName, OssFilePath);
                getObjectRequest.StreamTransferProgress += streamProgressCallback;
                var ossObject = ossClient.GetObject(getObjectRequest);
                using (var requestStream = ossObject.Content)
                {

                    int index = OssFilePath.LastIndexOf('/');

                    if (index != -1)
                    {
                        OssFileName = OssFilePath.Substring(index + 1, OssFilePath.Length - index - 1);
                    }
                    else
                        OssFileName = OssFilePath;



                    if (SaveFileName != "")
                        SavePath = Path.Combine(DownloadLocalDir, SaveFileName);
                    else
                        SavePath = Path.Combine(DownloadLocalDir, OssFileName);


                    using (var fs = File.Open(SavePath, FileMode.Create))
                    {
                        int length = 4 * 1024;
                        var buf = new byte[length];
                        do
                        {
                            length = requestStream.Read(buf, 0, length);
                            fs.Write(buf, 0, length);
                        } while (length != 0);
                    }
                }


                   Console.WriteLine("Get object:{0} succeeded", OssFilePath);
                ossTaskBackInfo.completed = true;
                return true;
            }
            catch (OssException ex)
            {
                   Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
                ossTaskBackInfo.completed = true;
                return false;
            }
            catch (Exception ex)
            {
                   Console.WriteLine("Failed with error info: {0}", ex.Message);
                ossTaskBackInfo.completed = true;
                return false;
            }








        }
        #endregion

        private int CalculatePartCount(long totalSize, int partSize)
        {
            var partCount = (int)(totalSize / partSize);
            if (totalSize % partSize != 0)
            {
                partCount++;
            }
            return partCount;
        }
        private void streamProgressCallback(object sender, StreamTransferProgressArgs args)
        {

            progress = args.TransferredBytes * 1.0f / args.TotalBytes;
            ossTaskBackInfo.progress = progress;
        }

    }
    public enum RequestState
    {
        Working,Sucess, Faile
    }
    /// <summary>
    /// Oss请求结果
    /// </summary>
    public class OssTaskRequest
    {

        public float progress = 0;
        public bool completed = false;
        public byte[] content = null;
        public RequestState requestState = RequestState. Working;
    }


}
